﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

using MvcCms.Service.Cache;
using MvcCms.Service;
using MvcCms.Data;

using MvcCmsProjectTracker.Service;
using MvcCmsProjectTracker.ViewModels;
using System.Net.Mail;
using System.IO;
using Microsoft.Practices.ServiceLocation;
using MvcCms.Service.Models;
using MvcCms.Service.Logging;

namespace MvcCmsProjectTracker.Controllers
{
    public class BugController : MvcCms.Service.Code.BaseClasses.CMSControllerBase
    {
        #region Constructors     
        private readonly ICacheService _cacheService;
        private readonly IAccountService _accountService;
        private readonly IBugService _bugService;
        private readonly IProjectService _projectService;
        public BugController(ICacheService cacheService, IAccountService accountService, IProjectService projectService, IBugService bugService, ICmsService cmsService, IZoneService zoneService)
            : base(cmsService, zoneService, accountService)
        {
            _cacheService = cacheService;
            _accountService = accountService;
            _bugService = bugService;
            _projectService = projectService;
        }
        #endregion

        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Index(int? projectId)
        {
            var user = _accountService.GetUser();
            if (!projectId.HasValue)
            {
                projectId = _accountService.GetProfile(user.UserID).DefaultProjectID;                
            }
            var results = new BugIndexViewModel();
            results.UsersProjects = _projectService.GetMyProjects(user.UserID).ToList();
            if (projectId.HasValue)
            {
                results.ActiveProjectID = projectId;
                results.Bugs = _bugService.GetBugsByProject(projectId.Value).ToList();
            }
            else
            {
                results.Bugs = new List<Bug>();
            }
            ViewBag.Title = "Manage Issues";
            return View(results);
        }

        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Search()
        {
            var results = new BugIndexViewModel();

            ViewBag.Title = "Search Issues";
            return View(results);
        }

        [Authorize(Roles = "Admin, Editor")]
        public JsonResult ListIssues(DataTablesRequest dataTablesRequest)
        {
            try
            {
                var columnsToReturn = "BugID,ProjectName,CategoryName,PriorityName,MileStoneName,Title,Status,CreatorUserName,Assigned,DateCreated,LastUpdate,Edit,Delete";
                var issues = _bugService.ListIssues(dataTablesRequest, columnsToReturn);
                var dataTablesFormatted = issues
                    .Select(i => new string[] {  
                                "<a href='/projecttracker/Project/"+i.ProjectID+"/Bug/Edit/"+i.BugID+"'>"+i.BugID+"</a>",
                                i.ProjectName,
                                i.CategoryName,
                                i.PriorityName,
                                i.MileStoneName, 
                                i.Title,                                                                                                  
                                i.Status,
                                i.CreatorUserName,
                                i.Assigned,
                                i.DateCreated.ToShortDateString(),
                                i.LastUpdate.ToShortDateString()
                            }).ToArray();

                var result = new DataTablesResponse
                {
                    iTotalRecords = issues.GetPagination.iTotalRecords,
                    iTotalDisplayRecords = issues.GetPagination.iTotalDisplayRecords,
                    sEcho = dataTablesRequest.sEcho,
                    sColumns = columnsToReturn,
                    aaData = dataTablesFormatted
                };

                return Json(result);
            }
            catch (Exception ex)
            {
                AppLogging.GetLogger().Error(ex.Message, ex);
                return Json(new { error = ex.Message });
            }
        }

        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult IncomingIssues()
        {

            var results = new BugIndexViewModel();
            results.UsersProjects = _projectService.GetHelpDeskProjects().ToList();
            int projectId = 0;
            if (results.UsersProjects.Count() > 0)
            {
                projectId = results.UsersProjects.FirstOrDefault().ProjectID;
                results.ActiveProjectID = projectId;
            }

            results.Bugs = _bugService.GetBugsByProject(projectId).ToList();

            ViewBag.Title = "Manage Incoming Issues";
            return View(results);
        }

        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Index(int? projectID, FormCollection collection)
        {
            try
            {
                var user = _accountService.GetUser();
                var results = new BugIndexViewModel();
                results.UsersProjects = _projectService.GetMyProjects(user.UserID).ToList();
                results.ActiveProjectID = int.Parse(collection["ActiveProjectID"]);

                return RedirectToAction("Index", "Bug", new
                {
                    projectID = collection["ActiveProjectID"]
                });
            }
            catch
            {
                return RedirectToAction("Index");
            }
        }

        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Create(int projectid)
        {
            var results = new BugCreateViewModel();
            var user = _accountService.GetUser();
            var project = _projectService.GetProject(projectid);
            if(project != null)
            {
                results.ProjectName = project.Name;
                results.Bug = new Bug()
                {
                    ProjectID = projectid,
                    AssignedTo = user
                };
            }

            results.ProjectMilestones = _projectService.GetProjectMilestones(projectid).ToList();
            results.ProjectCategories = _projectService.GetProjectCategories(projectid).ToList();
            results.ProjectPriorities = _projectService.GetProjectPriorities(projectid).ToList();
            results.ProjectStatuses = _projectService.GetProjectStatuses(projectid).ToList();
            results.ProjectMembers = _projectService.GetProjectMembers(projectid).ToList();

            if(results.ProjectMilestones.Count > 0)
                results.Bug.MilestoneID = results.ProjectMilestones[0].MilestoneID;
            if(results.ProjectPriorities.Count > 0)
                results.Bug.PriorityID = results.ProjectPriorities[0].PriorityID;
            if(results.ProjectStatuses.Count > 0)
                results.Bug.StatusID = results.ProjectStatuses[0].StatusID;
            ViewBag.Title = "Create Issue";
            return View(results);
        }

        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        [ValidateInput(false)]
        public ActionResult Create(Bug bug)
        {
            var user = _accountService.GetUser();
            var saved = false;
            if(ModelState.IsValid)
            {

                bug.CreatorUserName = user.UserName;
                bug.DateCreated = DateTime.Now;
                bug.LastUpdate = DateTime.Now;
                bug.Deleted = false;

                saved = _bugService.CreateBug(bug);
                                
                if (saved)
                {
                    return RedirectToAction("Index", new { projectId = bug.ProjectID });
                }
                else
                {
                    var results = new BugCreateViewModel();
                    results.Message = "There was a problem";
                    results.Bug = bug;
                    var project = _projectService.GetProject(bug.ProjectID);
                    if(project != null)
                    {
                        results.ProjectName = project.Name;
                    }

                    results.ProjectMilestones = _projectService.GetProjectMilestones(bug.ProjectID).ToList();
                    results.ProjectCategories = _projectService.GetProjectCategories(bug.ProjectID).ToList();
                    results.ProjectPriorities = _projectService.GetProjectPriorities(bug.ProjectID).ToList();
                    results.ProjectStatuses = _projectService.GetProjectStatuses(bug.ProjectID).ToList();
                    results.ProjectMembers = _projectService.GetProjectMembers(bug.ProjectID).ToList();

                    if(results.ProjectMilestones.Count > 0)
                        results.Bug.MilestoneID = results.ProjectMilestones[0].MilestoneID;
                    if(results.ProjectPriorities.Count > 0)
                        results.Bug.PriorityID = results.ProjectPriorities[0].PriorityID;
                    if(results.ProjectStatuses.Count > 0)
                        results.Bug.StatusID = results.ProjectStatuses[0].StatusID;

                    return View(results);
                }
            }
            else
            {
                var results = new BugCreateViewModel();
                results.Bug = bug;
                var project = _projectService.GetProject(bug.ProjectID);
                if(project != null)
                {
                    results.ProjectName = project.Name;
                }

                results.ProjectMilestones = _projectService.GetProjectMilestones(bug.ProjectID).ToList();
                results.ProjectCategories = _projectService.GetProjectCategories(bug.ProjectID).ToList();
                results.ProjectPriorities = _projectService.GetProjectPriorities(bug.ProjectID).ToList();
                results.ProjectStatuses = _projectService.GetProjectStatuses(bug.ProjectID).ToList();
                results.ProjectMembers = _projectService.GetProjectMembers(bug.ProjectID).ToList();

                if(results.ProjectMilestones.Count > 0)
                    results.Bug.MilestoneID = results.ProjectMilestones[0].MilestoneID;
                if(results.ProjectPriorities.Count > 0)
                    results.Bug.PriorityID = results.ProjectPriorities[0].PriorityID;
                if(results.ProjectStatuses.Count > 0)
                    results.Bug.StatusID = results.ProjectStatuses[0].StatusID;
                ViewBag.Title = "Create Issue";
                return View(results);
            }
        }

        // GET: /Bug/Edit/5
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Edit(int id)
        {
            var results = new BugEditViewModel();
            results.Bug = _bugService.GetBug(id);
            var project = _projectService.GetProject(results.Bug.ProjectID);

            results.ActiveProjectID = project.ProjectID;
            results.AvailableProjects = _projectService.GetAllProjects().ToList();

            if(project != null)
            {
                results.ProjectName = project.Name;
            }

            results.ProjectMilestones = _projectService.GetProjectMilestones(results.Bug.ProjectID).ToList();
            results.ProjectCategories = _projectService.GetProjectCategories(results.Bug.ProjectID).ToList();
            results.ProjectPriorities = _projectService.GetProjectPriorities(results.Bug.ProjectID).ToList();
            results.ProjectStatuses = _projectService.GetProjectStatuses(results.Bug.ProjectID).ToList();
            results.ProjectMembers = _projectService.GetProjectMembers(results.Bug.ProjectID).ToList();

            results.BugCommentViewModel = new BugCommentViewModel()
            {
                BugID = results.Bug.BugID,
                BugComments = _bugService.GetBugComments(results.Bug.BugID).ToList()
            };
            results.BugHistoryViewModel = new BugHistoryViewModel()
            {
                BugID = results.Bug.BugID,
                BugHistory = _bugService.GetBugHistories(results.Bug.BugID).ToList()
            };

            results.BugNotificationViewModel = new BugNotificationViewModel()
            {
                BugID = results.Bug.BugID,
                BugNotifications = _bugService.GetBugNotifications(results.Bug.BugID).ToList()
            };

            results.BugAttachmentViewModel = new BugAttachmentsViewModel()
            {
                BugID = results.Bug.BugID,
                BugAttachments = _bugService.GetBugAttachments(results.Bug.BugID).ToList()
            };
            ViewBag.Title = "Edit Issue";
            return View(results);
        }

        // POST: /Bug/Edit/5
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        [ValidateInput(false)]
        public ActionResult Edit(int id, FormCollection collection)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    var user = _accountService.GetUser();
                    Bug bug = _bugService.GetBug(id);

                    List<object[]> changes = new List<object[]>();
                    object oldValue;

                    if (collection["MilestoneID"] != null)
                    {
                        oldValue = bug.MilestoneID ?? 0;
                        bug.MilestoneID = int.Parse(collection["MilestoneID"]);
                        changes.Add(new object[] { "Milestone", oldValue, bug.MilestoneID });
                    }

                    if (collection["CategoryID"] != null)
                    {
                        oldValue = bug.CategoryID ?? 0;
                        bug.CategoryID = int.Parse(collection["CategoryID"]);
                        changes.Add(new object[] { "Category", oldValue, bug.CategoryID });
                    }

                    if (collection["PriorityID"] != null)
                    {
                        oldValue = bug.PriorityID ?? 0;
                        bug.PriorityID = int.Parse(collection["PriorityID"]);
                        changes.Add(new object[] { "Priority", oldValue, bug.PriorityID });
                    }

                    if (collection["StatusID"] != null)
                    {
                        oldValue = bug.StatusID ?? 0;
                        bug.StatusID = int.Parse(collection["StatusID"]);
                        changes.Add(new object[] { "Status", oldValue, bug.StatusID });
                    }

                    if (collection["ProjectID"] != null)
                    {
                        oldValue = bug.ProjectID;
                        bug.ProjectID = int.Parse(collection["ProjectID"]);
                        changes.Add(new object[] { "Project", oldValue, bug.ProjectID });
                    }

                    oldValue = bug.Description ?? "";
                    bug.Description = collection["Description"];
                    changes.Add(new object[] { "Description", oldValue, bug.Description });

                    oldValue = bug.Title ?? "";
                    bug.Title = collection["Title"];
                    changes.Add(new object[] { "Title", oldValue, bug.Title });

                    oldValue = bug.AssignedTo.UserName ?? "";
                    bug.AssignedUserID = Guid.Parse(collection["AssignedUserID"]);
                    var assignedToUser = _accountService.GetUser(bug.AssignedUserID);
                    changes.Add(new object[] { "Assigned User", oldValue, assignedToUser.UserName });

                    oldValue = bug.LastUpdate;
                    bug.LastUpdate = DateTime.Now;
                    changes.Add(new object[] { "Last Update", oldValue, bug.LastUpdate });

                    BugHistory newHistory = new BugHistory()
                    {
                        BugID = bug.BugID,
                        Changes = bug.GetBugChanges(changes),
                        UserName = User.Identity.Name,
                        DateCreated = DateTime.Now
                    };
                    bug.Histories.Add(newHistory);
                    _bugService.EditBug(bug);

                    //Send out email notifications
                    foreach (BugNotification notification in _bugService.GetBugNotifications(id))
                    {
                        MailAddress fromAddress = new MailAddress(_cacheService.GetCurrentPortal().AdminEmail);
                        string subject = string.Format("Bug {0} has been modified by {1}", id, User.Identity.Name);
                        string body = newHistory.Changes;
                        MailMessage message = new MailMessage()
                        {
                            From = fromAddress,
                            Subject = subject,
                            Body = body,
                            IsBodyHtml = true
                        };
                        MvcCms.Service.Code.Email.MvcCmsEmails.SendMessage(user.Email, message);
                    }

                    return RedirectToAction("Index", new { projectId = bug.ProjectID });
                }
                catch
                {
                    ViewBag.Title = "Edit Issue";
                    return View();
                }
            }
            else
            {
                return RedirectToAction("Edit", id);
            }

        }

        // GET: /Bug/SetIssueProject/5
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult SetIssueProject(int id)
        {
            var results = new BugEditViewModel();
            results.Bug = _bugService.GetBug(id);
            results.ProjectName = results.Bug.Project.Name;
            var user = _accountService.GetUser();

            results.UsersProjects = _projectService.GetNonHelpDeskProjects().ToList();

            ViewBag.Title = "Set Project for Incoming Issue";
            return View(results);
        }

        // POST: /Bug/SetIssueProject/5
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult SetIssueProject(Bug editedIssue)
        {
            var issueToEdit = _bugService.GetBug(editedIssue.BugID);
            issueToEdit.ProjectID = editedIssue.ProjectID;
            issueToEdit.Title = editedIssue.Title;
            _bugService.EditBug(issueToEdit);
            return RedirectToAction("Edit", new { id = issueToEdit.BugID });
        }

        // POST: /Bug/PromoteTicket/5
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        [ValidateInput(false)]
        public ActionResult PromoteTicket(int id)
        {
            var ticketService = ServiceLocator.Current.GetInstance<ITicketService>();
            var ticketToPromote = ticketService.GetTicket(id);
            var user = _accountService.GetUser();
            var bugToCreate = new Bug
            {
                Title = ticketToPromote.Title,
                CreatorUserName = user.UserName,
                AssignedUserID = user.UserID,
                Description = ticketToPromote.Description,
                DateCreated = DateTime.Now,
                LastUpdate = DateTime.Now,
                ProjectID = ticketToPromote.ProjectID
            };
            ticketToPromote.DeveloperIssue = bugToCreate;

            if (!_bugService.CreateBug(bugToCreate))
            {
                var results = new BugEditViewModel
                {
                    Message = "There was a problem promoting the ticket."
                };
                ViewBag.Title = "Promote Failed";
                return View(results);
            }
            return RedirectToAction("SetIssueProject", new { id = bugToCreate.BugID });
        }

        // GET: /Bug/Delete/5
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Delete(int id)
        {
            try
            {
                Bug bug = _bugService.GetBug(id);

                return View(bug);
            }
            catch
            {
                return View();
            }
        }

        // POST: /Bug/Delete/5
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult Delete(int id, FormCollection collection)
        {
            try
            {
                Bug bug = _bugService.GetBug(id);
                int projectId = bug.ProjectID;
                _bugService.DeleteBug(bug);
                _bugService.Save();
                return RedirectToAction("Index", new { projectId = projectId });
            }
            catch
            {
                Bug bug = _bugService.GetBug(id);

                return View(bug);
            }
        }

        // AJAX: /Bug/DeleteComment/2
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public PartialViewResult DeleteComment(int id)
        {
            BugComment comment = _bugService.GetBugComment(id);
            int bugID = comment.BugID;
            _bugService.DeleteBugComment(comment);
            _bugService.Save();
            var results = new BugCommentViewModel
            {
                Message = "Comment has been removed from the bug.",
                BugID = bugID,
                BugComments = _bugService.GetBugComments(bugID).ToList()
            };

            return PartialView("BugComments", results);
        }

        // AJAX: /Bug/AddComment/2

        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        [ValidateInput(false)]
        public PartialViewResult AddComment(int id, FormCollection collection)
        {
            BugComment comment = new BugComment();
            comment.BugID = id;
            comment.Comment = collection["comment"];
            comment.DateCreated = DateTime.Now;
            comment.UserName = User.Identity.Name;

            _bugService.AddBugComment(comment);
            _bugService.Save();
            var results = new BugCommentViewModel
            {
                Message = "Comment has been added to the bug.",
                BugID = comment.BugID,
                BugComments = _bugService.GetBugComments(comment.BugID).ToList()
            };

            return PartialView("BugComments", results);
        }

        // POST: /Bug/Delete/5
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult DeleteNotification(int id)
        {
            BugNotification notification = _bugService.GetBugNotification(id);
            int bugID = notification.BugID;
            _bugService.DeleteBugNotification(notification);
            _bugService.Save();
            var results = new BugNotificationViewModel
            {
                Message = "Notification has been deleted from the bug.",
                BugID = bugID,
                BugNotifications = _bugService.GetBugNotifications(bugID).ToList()
            };

            return PartialView("BugNotifications", results);
        }

        // AJAX: /Bug/AddNotification/2
        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public PartialViewResult AddNotification(int id)
        {
            BugNotification notification = new BugNotification();
            notification.BugID = id;
            notification.UserName = User.Identity.Name;

            _bugService.AddBugNotification(notification);
            _bugService.Save();
            var results = new BugNotificationViewModel
            {
                Message = "Notification has been added to the bug.",
                BugID = notification.BugID,
                BugNotifications = _bugService.GetBugNotifications(notification.BugID).ToList()
            };

            return PartialView("BugNotifications", results);
        }

        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult AddAttachment(int id, FormCollection collection)
        {
            BugAttachment attachment = new BugAttachment();
            attachment.BugID = id;
            attachment.UserName = User.Identity.Name;
            attachment.ContentType = Request.Files["file"].ContentType;

            Stream fileStream = Request.Files["file"].InputStream;
            attachment.FileName = Path.GetFileName(Request.Files["file"].FileName);
            int fileLength = Request.Files["file"].ContentLength;
            byte[] fileData = new byte[fileLength];
            fileStream.Read(fileData, 0, fileLength);
            attachment.Attachment = fileData;

            _bugService.AddBugAttachment(attachment);
            _bugService.Save();
            return RedirectToAction("Edit", "Bug", new
            {
                id = id
            });
        }

        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public PartialViewResult DeleteAttachment(int id)
        {
            BugAttachment attachment = _bugService.GetBugAttachment(id);
            int bugID = attachment.BugID;
            _bugService.DeleteBugAttachment(attachment);
            _bugService.Save();
            var results = new BugAttachmentsViewModel
            {
                Message = "Attachment has been deleted from the bug.",
                BugID = bugID,
                BugAttachments = _bugService.GetBugAttachments(bugID).ToList()
            };

            return PartialView("BugAttachments", results);
        }

        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public FileContentResult GetAttachment(int id)
        {
            BugAttachment attachment = _bugService.GetBugAttachment(id);

            return File(attachment.Attachment, attachment.ContentType, attachment.FileName);

        }

        [HttpPost]
        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult AddRelated(int id, int relatedID)
        {
            Bug parentBug = _bugService.GetBug(id);
            Bug relatedBug = _bugService.GetBug(relatedID);

            if(relatedBug == null)
            {
                ViewData.ModelState.AddModelError("relatedID", "Bug does not exists");
            }
            else
            {
                parentBug.RelatedBugs.Add(relatedBug);

                _bugService.Save();
            }

            return PartialView("BugRelated", parentBug);
        }

        [Authorize(Roles = "Admin, HelpDeskAdmin")]
        public ActionResult RemoveRelated(int id, int relatedID)
        {
            Bug parentBug = _bugService.GetBug(id);
            Bug relatedBug = _bugService.GetBug(relatedID);

            parentBug.RelatedBugs.Remove(relatedBug);

            _bugService.Save();

            return PartialView("BugRelated", parentBug);
        }      
    }
}
